package com.whfc.fvs.service.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.vs.model.v20181212.*;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.ListData;
import com.whfc.common.result.PageData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.DateUtil;
import com.whfc.common.util.JSONUtil;
import com.whfc.common.vs.aliyun.VsProperties;
import com.whfc.fvs.dao.FvsDeviceMapper;
import com.whfc.fvs.dao.FvsRecordMapper;
import com.whfc.fvs.dao.FvsStreamMapper;
import com.whfc.fvs.dto.*;
import com.whfc.fvs.entity.FvsDevice;
import com.whfc.fvs.entity.FvsStream;
import com.whfc.fvs.enums.FvsDevicePtzOption;
import com.whfc.fvs.param.FvsDeviceAddParam;
import com.whfc.fvs.service.FvsPlatformService;
import com.whfc.fvs.service.factroy.FvsPlatformConstant;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Date;
import java.util.List;

/**
 * @author : qzexing
 * @version : 1.0
 * @Description : 阿里云RTMP service
 * @date : 2020/4/30 13:23
 */
@Service(FvsPlatformConstant.ALIYUN_RTMP_SERVICE)
public class FvsAliyunRTMPVsServiceImpl implements FvsPlatformService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private FvsDeviceMapper fvsDeviceMapper;

    @Autowired
    private FvsStreamMapper fvsStreamMapper;

    @Autowired
    private FvsRecordMapper fvsRecordMapper;

    @Autowired
    private VsProperties vsProperties;

    private IAcsClient client;

    @PostConstruct
    public void postConstruct() {
        DefaultProfile profile = DefaultProfile.getProfile(vsProperties.getRegionId(), vsProperties.getAccessKeyId(), vsProperties.getAccessKeySecret());
        client = new DefaultAcsClient(profile);
    }

    @PreDestroy
    public void preDestroy() {
        client.shutdown();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addDevice(FvsDeviceDTO fvsDeviceDTO, FvsDeviceAddParam deviceAddParam) {
        String streamId = deviceAddParam.getUsername();
        if (StringUtils.isEmpty(streamId)) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "设备流ID不能为空");
        }
        //获取流的信息
        AliyunStreamInfoDTO streamInfoDTO = getStreamInfo(null, streamId);
        if (streamInfoDTO == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "该设备流不存在.");
        }
        FvsDevice fvsDevice = new FvsDevice();
        fvsDevice.setId(fvsDeviceDTO.getId());
        fvsDevice.setUsername(streamId);
        fvsDevice.setAliStreamId(streamInfoDTO.getId());
        fvsDevice.setAliGroupId(streamInfoDTO.getGroupId());
        Integer state = "on".equals(streamInfoDTO.getStatus()) ? 1 : 0;
        fvsDevice.setDeviceStatus(1);
        fvsDevice.setStreamStatus(state);
        fvsDeviceMapper.updateByPrimaryKeySelective(fvsDevice);
    }


    @Override
    public void deleteDevice(FvsDeviceDTO fvsDeviceDTO) {
        stopStream(fvsDeviceDTO.getAliStreamId());
    }

    @Override
    public String getSnapshotUrl(FvsDeviceDTO fvsDeviceDTO) {
        String snapshotUrl = "";
        if (fvsDeviceDTO != null) {
            snapshotUrl = fvsDeviceDTO.getSnapshotUrl();
        }
        return snapshotUrl;
    }

    @Override
    public FvsStreamDTO getStreamUrl(FvsDeviceDTO fvsDeviceDTO) {
        Integer deviceId = fvsDeviceDTO.getId();
        FvsStream fvsStream = new FvsStream();
        FvsStreamDTO fvsStreamDTO = fvsStreamMapper.selectByDeviceId(deviceId);
        if (fvsStreamDTO == null || fvsStreamDTO.getExpireTime().getTime() < System.currentTimeMillis()) {
            if (fvsStreamDTO != null) {
                fvsStream.setId(fvsStreamDTO.getId());
            }
            String streamId = fvsDeviceDTO.getAliStreamId();
            String hlsStreamUrl = getStreamPlayUrl(streamId, "hls");
            String rtmpStreamUrl = getStreamPlayUrl(streamId, "rtmp");
            fvsStream.setHls(hlsStreamUrl);
            fvsStream.setRtmp(rtmpStreamUrl);
            //直播地址过期时间 分钟
            Date expireTime = DateUtil.addMinutes(new Date(), 30);
            fvsStream.setExpireTime(expireTime);
            fvsStream.setDeviceId(deviceId);
            fvsStreamMapper.insertOrUpdate(fvsStream);
            fvsStreamDTO = new FvsStreamDTO();
            BeanUtils.copyProperties(fvsStream, fvsStreamDTO);
        }
        return fvsStreamDTO;
    }

    @Override
    public ListData<FvsRecordDTO> getRecordList(FvsDeviceDTO fvsDeviceDTO, Date startTime, Date endTime) {
        ListData<FvsRecordDTO> listData = new PageData<>();
        List<FvsRecordDTO> recordList = fvsRecordMapper.selectByDeviceId(fvsDeviceDTO.getId(), startTime, endTime);
        listData.setList(recordList);
        return listData;
    }

    @Override
    public void ptz(FvsDeviceDTO fvsDeviceDTO, FvsDevicePtzOption devicePtzOption) {
    }

    @Override
    public FvsTokenDTO getToken(Integer deptId) {
        return null;
    }

    /**
     * 获取流信息
     *
     * @param appName    appName
     * @param streamName streamName
     * @return AliyunStreamInfoDTO
     */
    public AliyunStreamInfoDTO getStreamInfo(String appName, String streamName) {
        AliyunStreamInfoDTO streamInfoDTO = null;
        DescribeStreamsRequest request = new DescribeStreamsRequest();
        if (StringUtils.isNotEmpty(appName)) {
            request.setApp(appName);
        }
        request.setName(streamName);
        try {
            DescribeStreamsResponse response = client.getAcsResponse(request);
            if (response != null) {
                List<DescribeStreamsResponse.Stream> streams = response.getStreams();
                if (streams != null && !streams.isEmpty()) {
                    streamInfoDTO = new AliyunStreamInfoDTO();
                    BeanUtils.copyProperties(streams.get(0), streamInfoDTO);
                }
            }
            return streamInfoDTO;
        } catch (Exception e) {
            logger.error("获取流信息失败", e);
            throw new BizException(ResultEnum.FAILURE.getCode(), "获取流信息失败");
        }
    }

    private String getStreamPlayUrl(String streamId, String protocol) {
        String streamUrl = null;
        try {
            //获取流的播放地址
            DescribeStreamURLRequest request = new DescribeStreamURLRequest();
            request.setId(streamId);
            request.setOutProtocol(protocol);
            request.setAuthKey(vsProperties.getAuthKey());
            DescribeStreamURLResponse response = client.getAcsResponse(request);
            logger.info("获取监控播放地址,streamId:{},response:{}", streamId, JSONUtil.toString(response));
            if (response == null || StringUtils.isEmpty(response.getBizUrl())) {
                throw new BizException(ResultEnum.FAILURE.getCode(), "获取直播播放地址失败");
            }
            streamUrl = response.getBizUrl().replace("http", "https");
        } catch (Exception ex) {
            logger.error("获取监控播放地址失败", ex);
            throw new BizException(ResultEnum.FAILURE.getCode(), "获取直播播放地址失败");
        }
        return streamUrl;
    }

    /**
     * 停止流
     *
     * @param streamId streamId
     */
    private void stopStream(String streamId) {
        try {
            StopStreamRequest request = new StopStreamRequest();
            request.setId(streamId);
            StopStreamResponse response = client.getAcsResponse(request);
            logger.info("停止流,response:{}", JSONUtil.toString(response));
        } catch (Exception e) {
            logger.error("停止流失败", e);
        }
    }
}
